﻿using System;
using System.Collections.Generic;
//From http://www.galasoft-lb.ch/mydotnet/GalaSoftLb.Utilities/flags-extracter.aspx

namespace TheDealmap.Util
{
    // Class definition *********************************************************
    /// <summary>
    /// Converts an integer value into the corresponding enumerated flags,
    /// returned in an array.
    /// </summary>
    /// <typeparam name="T">An Enumeration with the <see cref="FlagsAttribute"/> set.
    /// <para>The enumeration constants must be in powers of two, that is, 1, 2, 4, 8,
    /// and so on. This means the individual flags in combined enumeration constants do
    /// not overlap.</para></typeparam>
   
    public class CFlagsExtracter<T>
    {
 

        /// <summary>
        /// Contains the enumerated flags corresponding to the integer value
        /// passed to the constructor.
        /// </summary>
        private List<T> m_leFlags = new List<T>();
 
        /// <summary>
        /// Contains the enumerated flags corresponding to the integer value
        /// passed to the constructor.
        /// </summary>
        public T[] aeFlags
        {
            get
            {
                return m_leFlags.ToArray();
            }
        }

        /// <summary>
        /// Converts an integer value into the corresponding enumerated flags,
        /// returned in an array.
        /// </summary>
        /// <param name="iFlags">An integer corresponding to the flags set. For example,
        /// binary 100101101 = decimal 301</param>
        /// <returns>An array of enumerated values of the type parameter T.</returns>
        public static T[] ExtractFlags(int iFlags)
        {
            return new CFlagsExtracter<T>(iFlags).aeFlags;
        }


        // ------------------------------------------------------------------------
        /// <summary>
        /// Creates a new instance of the extracter with its property
        /// <see cref="aeFlags" /> set accordingly to the parameter iFlags.
        /// </summary>
        /// <param name="iFlags">An integer corresponding to the flags set. For example,
        /// binary 100101101 = decimal 301</param>
        public CFlagsExtracter(int iFlags)
        {
            // Check if the "T" Enum is correctly qualified as "Flags"
            Type oEnumType = typeof(T);
            if (oEnumType.GetCustomAttributes(typeof(FlagsAttribute), false).Length == 0)
            {
                // RESX
                throw new ArgumentException(String.Format("The type {0} is not an enum, or not a Flags enumeration", oEnumType.FullName));
            }

            // GetValues returns the values sorted by the binary value of the enum
            Array aValues = System.Enum.GetValues(typeof(T));
            T[] aeValues = (T[])aValues;
            int[] aiValues = (int[])aValues;
           // T combined = default(T);

            for (int index = 0; index < aiValues.Length; index++)
            {
                if (aiValues[index] > 0)
                {
                    int iTest = aiValues[index] & iFlags;
                    if (iTest == aiValues[index])
                    {
                        m_leFlags.Add(aeValues[index]);
                    }
                }
            }
        }

    }
}